package cn.chaos.bio01;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;

public class BruteForceCoding {
    
    private static byte byteVal = 101;
    private static short shortVal = 10001;
    private static int intVal = 100000001;
    private static long longVal = 1000000000001L;
    
    private final static int BSIZE = Byte.SIZE / Byte.SIZE;
    private final static int SSIZE = Short.SIZE / Byte.SIZE;
    private final static int ISIZE = Integer.SIZE / Byte.SIZE;
    private final static int LSIZE = Long.SIZE / Byte.SIZE;
    
    private static final int BYTEMASK = 0xFF; // 8 bite
    
    /**
     * 将数组中的每个字节作为一个无符号十进制数打印出来。
     * 
     * @param bArray
     * @return
     */
    public static String byteArrayToDecimalString(byte[] bArray) {
        
        StringBuilder rtn = new StringBuilder();
        for (byte b : bArray) {
            rtn.append(b & BYTEMASK).append(" ");
        }
        
        return rtn.toString();
    }
    
    public static int encodeIntBigEndian(byte[] dst, long val, int offset, int size) {
       
        System.out.println("offset == "+ offset +", size = "+ size);
        for (int i = 0; i < size; i++) {
            byte b = (byte) (val >> ((size -i -1) * Byte.SIZE));
            System.out.println(">> "+ (b & BYTEMASK));
            dst[offset++] = b;
        }
        System.out.println(byteArrayToDecimalString(dst));
        return offset;
    }
    
    public static long decodeIntBigEndian(byte[] val, int offset, int size ) {
        
        long rtn = 0;
        for (int i = 0; i < size; i++) {
            rtn = (rtn << Byte.SIZE ) | ((long) val[offset + i] & BYTEMASK);
        }
        
        return rtn;
    }
    
    public static void main(String[] args) {
        
        run2();
        run1();
        
        System.out.println("----------");
        
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        DataOutputStream out = new DataOutputStream(buf);
        
        try {
            out.writeByte(byteVal);
            out.writeShort(shortVal);
            out.writeInt(intVal);
            out.writeLong(longVal);
            out.flush();
            byte[] msg = buf.toByteArray();
            System.out.println(byteArrayToDecimalString(msg));
            buf.close();
            out.close();
        } catch (IOException e){
            e.printStackTrace();
        }

        
        
    }

    public static void run2() {
 
        byte[] message = new byte[ISIZE];
        
        int offset = encodeIntBigEndian(message, 256, 0, ISIZE);
        
        System.out.println("offset = "+ offset);
        
        long v = decodeIntBigEndian(message, 0, ISIZE);
        
        System.out.println("v = "+ v);
    }
    
    public static void run1(){

        byte[] message = new byte[BSIZE + SSIZE + ISIZE +LSIZE];
        
        int offset = encodeIntBigEndian(message, byteVal, 0, BSIZE);
        offset = encodeIntBigEndian(message, shortVal, offset, SSIZE);
        offset = encodeIntBigEndian(message, intVal, offset, ISIZE);
        
        encodeIntBigEndian(message, longVal, offset, LSIZE);
        
        System.out.println("Encoded message: "+ byteArrayToDecimalString(message));
        
        // Decode serveral fields
        long value = decodeIntBigEndian(message, BSIZE, SSIZE);
        System.out.println("Decoded short = "+ value);
        value = decodeIntBigEndian(message, BSIZE + SSIZE + ISIZE , LSIZE);
        System.out.println("Decoded long = "+ value);
        
        // Demonstrate dangers of conversion
        offset = 4;
        value = decodeIntBigEndian(message, offset, BSIZE);
        System.out.println("Decode value (offset "+ offset +", size "+ BSIZE  +" ) =" + 
                value );
        
        value = decodeIntBigEndian(message, offset, BSIZE);
        
        byte bVal = (byte) decodeIntBigEndian(message, offset, BSIZE);
        
        System.out.println("Same value as byte = "+ bVal);
    }
}
